/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.bopet.jocadv.core;

import eu.bopet.jocadv.core.datum.Axis;
import eu.bopet.jocadv.core.datum.CSys;
import eu.bopet.jocadv.core.datum.Plane;
import eu.bopet.jocadv.core.datum.Point;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

/**
 * This abstract class represents components
 *
 * @author bocskapeter
 */
public class Component implements Serializable, Refreshable {

    // first component id
    private static long iD = 0;
    // unique component id
    private final long id;
    // name of the component
    private String name;
    // status of the component
    private int status;
    private final List<Component> componentList;
    private final List<Element> elementList;
    private final List<Constraint> constraintList;
    private Vector3D maxGeomLimit;
    private Vector3D minGeomLimit;

    /**
     * Generates a new id
     *
     * @return new id as long
     */
    public static long getNewId() {
        return iD++;
    }

    public static Component getNewComponent() {
        Component component = new Component("Component");
        component.setMinGeomLimit(new Vector3D(-5, -5, -5));
        component.setMaxGeomLimit(new Vector3D(5, 5, 5));
        
        Point origin = Point.getDefaultOrigin();
        component.addElement(origin);

        Axis x = Axis.getDefaultX(origin.getPoint());
        component.addElement(x);

        Axis y = Axis.getDefaultY(origin.getPoint());
        component.addElement(y);

        Axis z = Axis.getDefaultZ(origin.getPoint());
        component.addElement(z);

        CSys cs = CSys.getDefaultCSys(origin.getPoint());
        component.addElement(cs);

        Plane p1 = Plane.getNewPlane(origin.getPoint(), x.getDirection());
        component.addElement(p1);
        Plane p2 = Plane.getNewPlane(origin.getPoint(), y.getDirection());
        component.addElement(p2);
        Plane p3 = Plane.getNewPlane(origin.getPoint(), z.getDirection());
        component.addElement(p3);

        component.refreshLimits(component.getMaxGeomLimit(), component.getMinGeomLimit());

        return component;
    }

    /**
     * Gives the id of the component
     *
     * @return id of the component as long
     */
    public long getId() {
        return id;
    }

    /**
     * Gives the name of the component
     *
     * @return name of the component as String
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the name of the component
     *
     * @param name String
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Gives the status of the component
     *
     * @return status of the component as int
     */
    public int getStatus() {
        return status;
    }

    /**
     * Sets the status of the component
     *
     * @param status int
     */
    public void setStatus(int status) {
        this.status = status;
    }

    /**
     * Default constructor, builds a new component with new id and with the
     * given name
     *
     * @param name String
     */
    public Component(String name) {
        this.id = Component.getNewId();
        this.name = name + id;
        this.status = 0;
        this.componentList = new ArrayList<Component>();
        this.elementList = new ArrayList<Element>();
        this.constraintList = new ArrayList<Constraint>();
    }
    
    public Component getComponent(long id) {
        Iterator<Component> iterator = this.componentList.iterator();
        Component component;
        while (iterator.hasNext()) {
            component = iterator.next();
            if (component.getId() == id) {
                return component;
            }
        }
        return null;
    }

    public Element getElement(long id) {
        Iterator<Element> iterator = this.elementList.iterator();
        Element element;
        while (iterator.hasNext()) {
            element = iterator.next();
            if (element.getId() == id) {
                return element;
            }
        }
        return null;
    }

    public void addElement(Element element) {
        this.elementList.add(element);
    }

    public boolean removeElement(Element element) {
        if (this.elementList.contains(element)) {
            this.elementList.remove(element);
            return true;
        }
        return false;
    }

    public List<Element> getElementList() {
        return elementList;
    }

    public Constraint getConstraint(long id) {
        Iterator<Constraint> iterator = this.constraintList.iterator();
        Constraint constraint;
        while (iterator.hasNext()) {
            constraint = iterator.next();
            if (constraint.getId() == id) {
                return constraint;
            }
        }
        return null;
    }

    public List<Constraint> getConstraintList() {
        return constraintList;
    }

    public void addConstraint(Constraint constraint) {
        this.constraintList.add(constraint);
    }

    public void modifyConstraint(long id, Constraint constraint) {
        Constraint oldConstraint = this.getConstraint(id);
        oldConstraint.setElementList(constraint.getElementList());
        oldConstraint.setParameter(constraint.getParameter());
    }

    public boolean removeConstraint(Constraint constraint) {
        if (this.constraintList.contains(constraint)) {
            this.constraintList.remove(constraint);
            return true;
        }
        return false;
    }

    public Vector3D getMaxGeomLimit() {
        return maxGeomLimit;
    }

    public void setMaxGeomLimit(Vector3D maxGeomLimit) {
        this.maxGeomLimit = maxGeomLimit;
    }

    public Vector3D getMinGeomLimit() {
        return minGeomLimit;
    }

    public void setMinGeomLimit(Vector3D minGeomLimit) {
        this.minGeomLimit = minGeomLimit;
    }
    
    @Override
    public void refreshLimits(Vector3D max, Vector3D min) {
        Element element;
        Iterator<Element> iterator = elementList.iterator();

        while (iterator.hasNext()) {
            element = iterator.next();
            if (element instanceof Refreshable) {
                ((Refreshable) element).refreshLimits(max, min);
            }
        }
    }

    /**
     * Converts the component to String
     *
     * @return the component as String
     */
    @Override
    public String toString() {
        return "Component{" + "id=" + id + ", name=" + name + ", status=" + status + "\n ComponentList=" + componentList + "\n ElementList=" + elementList + "\n ConstraintList=" + constraintList + "\n maxGeomLimit=" + maxGeomLimit + ", minGeomLimit=" + minGeomLimit + '}';
    }

}
